use crate::error::AppError;
use codegraph_core::config::*;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::sync::Arc;
use tauri::{AppHandle, State, Emitter};
use tokio::sync::RwLock;

/// Configuration manager state for Tauri
pub struct ConfigManagerState {
    pub manager: Arc<ConfigManager>,
    pub workspace_manager: Arc<RwLock<Option<WorkspaceStateManager>>>,
}

impl ConfigManagerState {
    pub fn new() -> Result<Self, AppError> {
        let manager = Arc::new(ConfigManager::with_file_storage()
            .map_err(|e| AppError::config(e.to_string()))?);

        Ok(Self {
            manager,
            workspace_manager: Arc::new(RwLock::new(None)),
        })
    }
}

/// Initialize configuration system
#[tauri::command]
pub async fn init_config(
    state: State<'_, ConfigManagerState>,
) -> Result<AppConfig, AppError> {
    state.manager.initialize().await
        .map_err(|e| AppError::config(e.to_string()))?;
    
    let config = state.manager.get_config().await;
    Ok(config)
}

/// Get current configuration
#[tauri::command]
pub async fn get_config(
    state: State<'_, ConfigManagerState>,
) -> Result<AppConfig, AppError> {
    let config = state.manager.get_config().await;
    Ok(config)
}

/// Get a specific configuration value
#[tauri::command]
pub async fn get_config_value(
    key: String,
    state: State<'_, ConfigManagerState>,
) -> Result<Option<serde_json::Value>, AppError> {
    state.manager.get_value(&key).await
        .map_err(|e| AppError::config(e.to_string()))
}

/// Set a specific configuration value
#[tauri::command]
pub async fn set_config_value(
    key: String,
    value: serde_json::Value,
    state: State<'_, ConfigManagerState>,
) -> Result<(), AppError> {
    state.manager.set_value(&key, value).await
        .map_err(|e| AppError::config(e.to_string()))
}

/// Reset configuration to defaults
#[tauri::command]
pub async fn reset_config(
    state: State<'_, ConfigManagerState>,
) -> Result<(), AppError> {
    state.manager.reset_to_defaults().await
        .map_err(|e| AppError::config(e.to_string()))
}

/// Reset a specific configuration section
#[tauri::command]
pub async fn reset_config_section(
    section: String,
    state: State<'_, ConfigManagerState>,
) -> Result<(), AppError> {
    state.manager.reset_section(&section).await
        .map_err(|e| AppError::config(e.to_string()))
}

/// Export configuration to JSON string
#[tauri::command]
pub async fn export_config(
    state: State<'_, ConfigManagerState>,
) -> Result<String, AppError> {
    state.manager.export_config().await
        .map_err(|e| AppError::config(e.to_string()))
}

/// Import configuration from JSON string
#[tauri::command]
pub async fn import_config(
    config_json: String,
    state: State<'_, ConfigManagerState>,
) -> Result<(), AppError> {
    state.manager.import_config(&config_json).await
        .map_err(|e| AppError::config(e.to_string()))
}

/// Create a backup of current configuration
#[tauri::command]
pub async fn create_config_backup(
    state: State<'_, ConfigManagerState>,
) -> Result<String, AppError> {
    let backup_path = state.manager.create_backup().await
        .map_err(|e| AppError::config(e.to_string()))?;
    
    Ok(backup_path.to_string_lossy().to_string())
}

/// List available configuration backups
#[tauri::command]
pub async fn list_config_backups(
    state: State<'_, ConfigManagerState>,
) -> Result<Vec<ConfigBackupInfo>, AppError> {
    let backups = state.manager.list_backups().await
        .map_err(|e| AppError::config(e.to_string()))?;
    
    let backup_infos: Vec<ConfigBackupInfo> = backups
        .into_iter()
        .map(|backup| ConfigBackupInfo {
            path: backup.to_string_lossy().to_string(),
            // Note: In a real implementation, you'd extract metadata from the backup file
            created_at: chrono::Utc::now().to_rfc3339(),
            size: 0, // Would be calculated from file
        })
        .collect();
    
    Ok(backup_infos)
}

/// Restore configuration from backup
#[tauri::command]
pub async fn restore_config_backup(
    backup_path: String,
    state: State<'_, ConfigManagerState>,
) -> Result<(), AppError> {
    let path = PathBuf::from(backup_path);
    state.manager.restore_backup(&path).await
        .map_err(|e| AppError::config(e.to_string()))
}

/// Initialize workspace state manager
#[tauri::command]
pub async fn init_workspace(
    workspace_path: String,
    state: State<'_, ConfigManagerState>,
) -> Result<(), AppError> {
    let path = PathBuf::from(workspace_path);
    let workspace_manager = WorkspaceStateManager::with_workspace_path(&path)
        .map_err(|e| AppError::config(e.to_string()))?;
    
    let mut manager_guard = state.workspace_manager.write().await;
    *manager_guard = Some(workspace_manager);
    
    Ok(())
}

/// Get workspace state
#[tauri::command]
pub async fn get_workspace_state(
    state: State<'_, ConfigManagerState>,
) -> Result<Option<WorkspaceState>, AppError> {
    let manager_guard = state.workspace_manager.read().await;
    
    if let Some(manager) = manager_guard.as_ref() {
        let workspace_state = manager.load_state().await
            .map_err(|e| AppError::config(e.to_string()))?;
        Ok(Some(workspace_state))
    } else {
        Ok(None)
    }
}

/// Save workspace state
#[tauri::command]
pub async fn save_workspace_state(
    workspace_state: WorkspaceState,
    state: State<'_, ConfigManagerState>,
) -> Result<(), AppError> {
    let manager_guard = state.workspace_manager.read().await;
    
    if let Some(manager) = manager_guard.as_ref() {
        manager.save_state(&workspace_state).await
            .map_err(|e| AppError::config(e.to_string()))?;
        Ok(())
    } else {
        Err(AppError::config("Workspace not initialized".to_string()))
    }
}

/// Subscribe to configuration changes
#[tauri::command]
pub async fn subscribe_config_changes(
    app: AppHandle,
    state: State<'_, ConfigManagerState>,
) -> Result<(), AppError> {
    let mut receiver = state.manager.subscribe_to_changes();
    let app_handle = app.clone();
    
    tokio::spawn(async move {
        while let Ok(change_event) = receiver.recv().await {
            let _ = app_handle.emit("config-changed", &change_event);
        }
    });
    
    Ok(())
}

/// Get platform-specific configuration paths
#[tauri::command]
pub async fn get_config_paths() -> Result<ConfigPathsInfo, AppError> {
    let config_dir = ConfigPaths::config_dir()
        .map_err(|e| AppError::config(e.to_string()))?;
    let data_dir = ConfigPaths::data_dir()
        .map_err(|e| AppError::config(e.to_string()))?;
    let cache_dir = ConfigPaths::cache_dir()
        .map_err(|e| AppError::config(e.to_string()))?;
    let logs_dir = ConfigPaths::logs_dir()
        .map_err(|e| AppError::config(e.to_string()))?;
    
    Ok(ConfigPathsInfo {
        config_dir: config_dir.to_string_lossy().to_string(),
        data_dir: data_dir.to_string_lossy().to_string(),
        cache_dir: cache_dir.to_string_lossy().to_string(),
        logs_dir: logs_dir.to_string_lossy().to_string(),
    })
}

/// Check platform compatibility
#[tauri::command]
pub async fn check_platform_compatibility(
    config: AppConfig,
) -> Result<PlatformCompatibilityInfo, AppError> {
    let result = platform::PlatformConfig::is_compatible(&config);
    
    Ok(PlatformCompatibilityInfo {
        is_compatible: result.is_compatible,
        warnings: result.warnings,
        recommendations: result.recommendations,
    })
}

/// Apply platform-specific adjustments
#[tauri::command]
pub async fn apply_platform_adjustments(
    mut config: AppConfig,
) -> Result<AppConfig, AppError> {
    platform::PlatformConfig::adjust_for_platform(&mut config)
        .map_err(|e| AppError::config(e.to_string()))?;
    
    Ok(config)
}

// Serializable types for Tauri commands

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigBackupInfo {
    pub path: String,
    pub created_at: String,
    pub size: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigPathsInfo {
    pub config_dir: String,
    pub data_dir: String,
    pub cache_dir: String,
    pub logs_dir: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlatformCompatibilityInfo {
    pub is_compatible: bool,
    pub warnings: Vec<String>,
    pub recommendations: Vec<String>,
}
